import sys
from PyQt5.QtWidgets import (
    QGraphicsScene, QGraphicsView, QApplication, QWidget, QVBoxLayout, QGraphicsEllipseItem, QGraphicsLineItem
)
from PyQt5.QtGui import QPixmap, QCursor, QPainter, QColor, QPen, QBrush
from PyQt5.QtCore import Qt, QPointF, pyqtSignal, QObject, QPoint, QLineF
import logging


# 设置日志配置
logging.basicConfig(level=logging.INFO)


class PointShape(QGraphicsEllipseItem):
    def __init__(self, point_type, display_type, name, size, category, parent=None):
        super().__init__(-size / 2, -size / 2, size, size, parent)
        self.point_type = point_type
        self.display_type = display_type
        self.name = name
        self.category = category
        self.setVisible(True)

        # 设置点的颜色和边框
        self.setBrush(QBrush(QColor(0, 128, 255, 150)))  # 半透明蓝色
        self.setPen(QPen(QColor(0, 0, 0), 1))  # 黑色边框

    def setPos(self, position):
        if isinstance(position, (tuple, list)) and len(position) == 2:
            pose = QPointF(position[0], position[1])
        elif isinstance(position, QPointF):
            pose = position
        else:
            raise ValueError("Invalid position argument. Expected tuple/list of two elements or QPointF.")
        super().setPos(pose)
    # def setPos(self, pos):
    #     pose = QPointF(pos)
    #     super().setPos(pose)

    def updateDisplay(self, pose):  
        # 如果需要根据pose更新位置或其他属性，可以在这里实现
        self.setPos(pose)

    def getDisplayName(self):
        return self.name

class TopologyMap:
    class PointInfo:
        def __init__(self, pose, name):
            self.pose = pose  # 这里简化为一个位置
            self.name = name

        def toRobotPose(self):
            return self.pose

    def __init__(self):
        self.points = []

    def addPoint(self, point_info):
        self.points.append(point_info)

    def removePoint(self, name):
        self.points = [p for p in self.points if p.name != name]

    def getPoint(self, name):
        for point in self.points:
            if point.name == name:
                return point
        return None

    def updatePoint(self, name, point_info):
        for i, point in enumerate(self.points):
            if point.name == name:
                self.points[i] = point_info
                break


class DisplayManager:
    def __init__(self):
        pass

    def wordPose2Map(self, pose):
        # 简化实现，直接返回pose
        return pose

    def scenePoseToMap(self, pose):
        return pose

    def scenePoseToWord(self, pose):
        return pose


class FactoryDisplay:
    _instance = None

    def __init__(self):
        if FactoryDisplay._instance is not None:
            raise Exception("This class is a singleton!")
        else:
            self.displays = {}

    @staticmethod
    def Instance():
        if FactoryDisplay._instance is None:
            FactoryDisplay._instance = FactoryDisplay()
        return FactoryDisplay._instance

    def addDisplay(self, display):
        self.displays[display.getDisplayName()] = display

    def removeDisplay(self, display):
        if display.getDisplayName() in self.displays:
            del self.displays[display.getDisplayName()]

    def getDisplay(self, name):
        return self.displays.get(name, None)


class SceneManager(QGraphicsScene):
    def __init__(self, parent=None):
        super().__init__(parent)
        self.topology_map = TopologyMap()
        self.display_manager = DisplayManager()
        self.factory_display = FactoryDisplay.Instance()
        self.current_mode = "kStop"
        self.nav_goal_widget = None
        self.eraser_cursor = None
        if self.views():
            self.views()[0].setCursor(self.eraser_cursor)

    def loadTopologyMap(self):
        # 模拟加载拓扑图
        logging.info("Loading topology map...")
        # 添加一些示例点
        point1 = PointShape("kNavGoal", "DISPLAY_GOAL", "NAV_POINT_1", 8, "DISPLAY_MAP")
        point1.setPos(QPointF(100, 100))
        point2 = PointShape("kNavGoal", "DISPLAY_GOAL", "NAV_POINT_2", 8, "DISPLAY_MAP")
        point2.setPos(QPointF(200, 200))
        self.topology_map.addPoint(TopologyMap.PointInfo(point1.pos, point1.name))
        self.topology_map.addPoint(TopologyMap.PointInfo(point2.pos, point2.name))
        self.addDisplays()
        logging.info("Topology map loaded successfully!")

    def addDisplays(self):
        for point_info in self.topology_map.points:
            pose = point_info.pose()  # 假设 pose 是一个方法，需要调用它
            print(f"pose: {pose}, type: {type(pose)}")  # 调试信息
            
            if not isinstance(pose, (QPointF, QPoint)):
                raise ValueError(f"pose must be a QPointF or QPoint, got {type(pose)}")
            
            point = PointShape(
                pose, "DISPLAY_GOAL", point_info.name, 8, "DISPLAY_MAP"
            )
            point.setPos(pose)
            self.factory_display.addDisplay(point)
            self.addItem(point)


    def setEditMapMode(self, mode):
        self.current_mode = mode
        logging.info(f"Set edit mode: {mode}")
        # 根据模式调整光标或其他设置
        if mode == "kErase":
            self.setEraseCursor()
        elif mode == "kStop":
            self.getView().setCursor(Qt.ArrowCursor)
        elif mode == "kAddPoint":
            self.addNavPoint()
        elif mode == "kAddLine":
            self.drawLine()
        elif mode == "kAddArea":
            self.getView().setCursor(Qt.CrossCursor)

    def setEraseCursor(self):
        # 设置橡皮擦光标
        pixmap = QPixmap(20, 20)
        pixmap.fill(Qt.transparent)
        painter = QPainter(pixmap)
        painter.setBrush(QColor(255, 0, 0, 100))
        painter.drawEllipse(0, 0, 20, 20)
        painter.end()
        self.eraser_cursor = QCursor(pixmap, 10, 10)
        self.getView().setCursor(self.eraser_cursor)

    def mousePressEvent(self, event):
        pos = self.views()[0].mapToScene(event.pos().toPoint())
        if self.current_mode == "kAddPoint":
            self.addNavPoint(pos)
        elif self.current_mode == "kErase":
            self.eraseScenePointRange(pos, 30)
        super().mousePressEvent(event)

    def addNavPoint(self, pos):
        name = self.generatePointName("NAV_POINT")
        point = PointShape("kNavGoal", "DISPLAY_GOAL", name, 8, "DISPLAY_MAP")
        point.setPos(pos)
        point.setVisible(True)
        self.topology_map.addPoint(TopologyMap.PointInfo(pos, name))
        self.factory_display.addDisplay(point)
        self.addItem(point)
        logging.info(f"Added nav point: {name} at {pos}")

    def eraseScenePointRange(self, pos, range):
        # 简化实现，删除范围内的点
        items = self.items(pos)
        for item in items:
            if isinstance(item, PointShape) and item.display_type == "DISPLAY_GOAL":
                self.factory_display.removeDisplay(item)
                self.removeItem(item)
                self.topology_map.removePoint(item.name)
                logging.info(f"Erased point: {item.name}")

    def generatePointName(self, prefix):
        index = len(self.topology_map.points) + 1
        name = f"{prefix}_{index}"
        return name

    def getView(self):
        if self.views():
            return self.views()[0]
        else:
            return None

    def drawLine(self, start_pos, end_pos, pen=None):
        """
        在场景中绘制一条线。
        :param start_pos: 线条起点位置 (QPointF)
        :param end_pos: 线条终点位置 (QPointF)
        :param pen: 线条画笔样式 (QPen)
        """
        line = QGraphicsLineItem(QLineF(start_pos, end_pos))
        if pen is None:
            pen = QPen(Qt.black, 2, Qt.SolidLine, Qt.RoundCap, Qt.RoundJoin)
        line.setPen(pen)
        self.addItem(line)

    def setMoveEnable(self, enable=True):
        """
        启用或禁用场景中所有可移动项目的移动。
        :param enable: 是否启用移动 (bool)
        """
        for item in self.items():
            if hasattr(item, 'setFlag') and callable(item.setFlag):
                item.setFlag(item.ItemIsMovable, enable)



class DisplayView(QGraphicsView):
    def __init__(self, scene, parent=None):
        super().__init__(scene, parent)
        self.setSceneRect(0, 0, 800, 600)


if __name__ == "__main__":
    app = QApplication(sys.argv)
    main_window = QWidget()
    layout = QVBoxLayout()

    scene_manager = SceneManager()
    scene_manager.loadTopologyMap()

    view = DisplayView(scene_manager)
    layout.addWidget(view)
    main_window.setLayout(layout)
    main_window.show()

    # 设置编辑模式为添加点
    scene_manager.setEditMapMode("kErase")

    sys.exit(app.exec_())